/**
 *  \file   radio.c   RECEPTION
 *  \brief  eZ430-RF2500 1-hop radio
 *  \author Miora ANDRIAMANOHARISOA, Loic MINGHETTI
 *  \date   PFE 2011
 **/

#include "include.h"

#define MSG_SIZE 60
#define USE_CONFIGURATION_0
#define USER_RFCONFIG config0

// Chipcon
// Product = CC2500
// Chip version = E   (VERSION = 0x03)
// Crystal accuracy = 10 ppm
// X-tal frequency = 26 MHz
// RF output power = 0 dBm
// RX filterbandwidth = 541.666667 kHz
// Phase = 1
// Datarate = 249.938965 kBaud
// Modulation = (7) MSK
// Manchester enable = (0) Manchester disabled
// RF Frequency = 2432.999908 MHz
// Channel spacing = 199.951172 kHz
// Channel number = 0
// Optimization = Current
// Sync mode = (3) 30/32 sync word bits detected
// Format of RX/TX data = (0) Normal mode, use FIFOs for RX and TX
// CRC operation = (1) CRC calculation in TX and CRC check in RX enabled
// Forward Error Correction = (0) FEC disabled
// Length configuration = (1) Variable length packets, packet length configured by the first received byte after sync word.
// Packetlength = 255
// Preamble count = (2)  4 bytes
// Append status = 1
// Address check = (0) No address check
// FIFO autoflush = 0
// Device address = 0
// GDO0 signal selection = ( 6) Asserts when sync word has been sent / received, and de-asserts at the end of the packet
// GDO2 signal selection = (41) CHIP_RDY
const RF_SETTINGS config0 = {
    0x12,   // FSCTRL1   Frequency synthesizer control.
    0x00,   // FSCTRL0   Frequency synthesizer control.
    0x5D,   // FREQ2     Frequency control word, high byte.
    0x93,   // FREQ1     Frequency control word, middle byte.
    0xB1,   // FREQ0     Frequency control word, low byte.
    0x2D,   // MDMCFG4   Modem configuration.
    0x3B,   // MDMCFG3   Modem configuration.
    0xF3,   // MDMCFG2   Modem configuration.
    0x22,   // MDMCFG1   Modem configuration.
    0xF8,   // MDMCFG0   Modem configuration.
    0x05,   // CHANNR    Channel number.
    0x01,   // DEVIATN   Modem deviation setting (when FSK modulation is enabled).
    0xB6,   // FREND1    Front end RX configuration.
    0x10,   // FREND0    Front end TX configuration.
    0x18,   // MCSM0     Main Radio Control State Machine configuration.
    0x1D,   // FOCCFG    Frequency Offset Compensation Configuration.
    0x1C,   // BSCFG     Bit synchronization Configuration.
    0xC7,   // AGCCTRL2  AGC control.
    0x00,   // AGCCTRL1  AGC control.
    0xB0,   // AGCCTRL0  AGC control.
    0xEA,   // FSCAL3    Frequency synthesizer calibration.
    0x0A,   // FSCAL2    Frequency synthesizer calibration.
    0x00,   // FSCAL1    Frequency synthesizer calibration.
    0x11,   // FSCAL0    Frequency synthesizer calibration.
    0x59,   // FSTEST    Frequency synthesizer calibration.
    0x88,   // TEST2     Various test settings.
    0x31,   // TEST1     Various test settings.
    0x0B,   // TEST0     Various test settings.
    0x07,   // FIFOTHR   RXFIFO and TXFIFO thresholds.
    0x29,   // IOCFG2    GDO2 output pin configuration.
    0x06,   // IOCFG0D   GDO0 output pin configuration. Refer to SmartRF® Studio User Manual for detailed pseudo register explanation.
    0x04,   // PKTCTRL1  Packet automation control.
    0x05,   // PKTCTRL0  Packet automation control.
    0x00,   // ADDR      Device address.
    0xFF    // PKTLEN    Packet length.
};


/* ************************************************************
		  FONCTIONS RADIO DE BASE
 ************************************************************ */

#define IDLE 0
#define RX 1

static unsigned int radio_state;
static uint8_t buffer_rx_msg [MSG_SIZE]; 
static int     buffer_rx_rssi;
static char    buffer_rx_flag;

void prompt_radio_state() {
  printf("radio state = %u\r\n", radio_state);
}

/** 
  *  \fn void radio_init()
  *  \brief initialisation du chip radio
  *  \param nul
  *  configuration du port série spi
  *  configuration du convertisseur anal/num cc2500 à partir de la config2 définie plus haut (définition des bits de registres )
  *  annonce le buffer comme vide (buffer_rx_flag=0) jusqu'à ce qu'on reçoit klk chose en entrée 
  *  initialisation du buffer de la chip radio cc2500 
  *  attente d'une réception de message... ensuite execution de la fonction de call back  
*/
void radio_init()
{
  spi_init();	
  cc2500_init(); 
  cc2500_configure(& USER_RFCONFIG );  
  buffer_rx_flag = 0;	 
  cc2500_rx_register_buffer(buffer_rx_msg, MSG_SIZE);  
  cc2500_rx_register_cb(radio_cb);  
  cc2500_idle();
  radio_state = IDLE;
}

/** 
  *  \fn re_init_buffer()
  *  \brief fonction d'initialisation du buffer
  *  \param nul
**/
void re_init_buffer(void)
{
 buffer_rx_rssi = 0;
 buffer_rx_flag = 0;
}

void rx_start(void) {
  cc2500_rx_enter();
  radio_state = RX;
}

void radio_sleep(void) {
  if (buffer_rx_flag != 0) {
    buffer_rx_flag = 0;
  }
  cc2500_idle();
  radio_state = IDLE;
}

/** 
  *  \fn void radio_cb(uint8_t* buffer, int size, int8_t rssi) 
  *  \brief Fonction de call back exécutée à chaque réception. Stocke le message dans un biuffer, récupère rssi et flag. se remet en écoute juste après.  
  *  \param uint8_t* buffer : buffer temporaire du message reçu
  *  \param int size : taille du buffer temporaire 
  *  \param int8_t rssi : force de réception du signal "Receive Signal Strength Indicator"
  *  \brief copie le contenue du buffer temporaire dans buffer_rx_msg, précise le buffer_rx_rssi et annonce par le buffer_rx_flag que le vuffer est non vide
*/
void radio_cb(uint8_t* buffer, int size, int8_t rssi)  
{
    led_green_switch();
  switch (size) {
    case 0:
      printf("msg size 0\n");
      break;
    case -EEMPTY:
      printf("msg empty\n");
      break;
    case -ERXFLOW:
      printf("msg rx overflow\n");
      break;
    case -ERXBADCRC:
      printf("msg rx bad CRC\n");
      break;
    case -ETXFLOW:
      printf("msg tx overflow\n");
      break;
    default:
      if (size > 0) {
	memcpy(buffer_rx_msg, buffer, MSG_SIZE);
	buffer_rx_rssi = rssi;
	buffer_rx_flag = 1;
      }
      else {
	printf("msg packet error size=%d\n",size);
      }
      break;
    }
	cc2500_idle();
	radio_state = IDLE;
	if (!buffer_rx_flag) {
	  cc2500_rx_enter();
	  radio_state = RX;
	}
	
}

/** 
  *  \fn void tx(char* msg)
  *  \brief Fonctin d'envoie de message
  *  \param msg chaine de caractère
*/
void tx(char* msg){
  int msg_size = strlen(msg);  
  led_red_switch();
  cc2500_utx(msg,msg_size);
}

/** 
  *  \fn Msg rx()
  *  \brief reconstruit le message reçu à partir du contenue du buffer buffer_rx_msg
  *  \param nul
  *  \return Le message reçue 
  *  scrute si le buffer est rempli, dans ce cas, récupère les données du buffer et reconstruit un message et se met en veille
*/
Msg rx()
{  
  Msg msg;
    
  if (buffer_rx_flag == 1)
  {	
    char node_id_c[3];
    char hop_count_c[2];
    char node_dest_c[3];
    char msge_type_c[2];
    char num_preambule_c[3];
    char dest_id_final_c[3];
    char temperature_c[4];
    char origine_id_c[3];
    char num_mesure_c[3];
     
    memcpy(node_id_c, buffer_rx_msg, 2);
    memcpy(hop_count_c, &buffer_rx_msg[2], 1);
    memcpy(node_dest_c, &buffer_rx_msg[3], 2);
    memcpy(msge_type_c, &buffer_rx_msg[5], 1);   
    msg.source = atoi(node_id_c);
    msg.hop_count = atoi(hop_count_c);
    msg.destinataire = atoi(node_dest_c);
    msg.type = atoi(msge_type_c);
    printf("[DEBUG] node id : %d, src_hop_count : %d, dest_id : %d, type = %d",msg.source, msg.hop_count, msg.destinataire,msg.type);
    
    switch (msg.type) {
      case 1 :
	memcpy(num_preambule_c,&buffer_rx_msg[6],2);
	msg.num_preambule = atoi(num_preambule_c);
	printf(", num_preambule = %d\r\n",msg.num_preambule);
	break;
	
      case 2 : 
	printf("\r\n");
	break;
	
      case 3 :
	memcpy(dest_id_final_c, &buffer_rx_msg[6],2);
	memcpy(temperature_c, &buffer_rx_msg[8],3);
	memcpy(origine_id_c, &buffer_rx_msg[11],2);
	memcpy(num_mesure_c, &buffer_rx_msg[13],2);
	msg.id_relay = atoi(dest_id_final_c);
	msg.temperature = atoi(temperature_c);
	msg.origine_id = atoi(origine_id_c);
	msg.num_mesure = atoi(num_mesure_c); 
	printf(", relay choosen : %d, Temperature: %d,%d, origine_id : %d, num_mesure : %d\r\n",msg.id_relay,  msg.temperature/10, msg.temperature%10, msg.origine_id, msg.num_mesure);
	break;
    }

    msg.rssi = buffer_rx_rssi;
    msg.is_valid = 1;
    buffer_rx_flag = 0;
    
    cc2500_idle();
    radio_state = IDLE;
  }
  else
  {
    cc2500_rx_enter();
    msg.is_valid = 0;
    radio_state = RX;
  }
  
  return msg;	
}

